package core;

import effect.Effect;
import effect.EffectUtil;
import effect.Effect.EffectType;
import gui.HandViewPanel;
import gui.SelectionController;
import gui.StatusPanel;


import java.util.Observable;

import card.Card;
import card.CreatureCard;

import core.Rules.Turn;

/**
 * 
 * @author Oscar A class for controlling the turns of the game.
 */
public class TurnController extends Observable {
	public static TurnController me;

	public static TurnController getInstance() {
		if (me == null)
			me = new TurnController();
		return me;
	}

	public TurnController() {
		this.addObserver(StatusPanel.getInstance());
	}

	/**
	 * A method that changes the turn if appriopiate. Return either 0 or 1,
	 * which are added to the turn variable in Core.
	 * 
	 * @param l
	 * @return int
	 */
	public void changeTurn() {
		// TODO Oscar clean up and/or add comments

		Core.getInstance().addTurnCounter();
		int tc = Core.getInstance().getTurnCounter();
		Player previousPlayer = Core.getInstance().getCurrentPlayer();
		Player newCurrentPlayer = getNextPlayer();
		
		if (tc > Core.getInstance().getPlayers().size()) {
			Core.getInstance().changeCurrentPlayer(newCurrentPlayer, 1);
			Core.getInstance().resetTurnCounter();
		}
		Core.getInstance().changeCurrentPlayer(newCurrentPlayer, 0);

		SelectionController.getInstance().deselect();

		resetActionsForAllCards();
		addIncome(newCurrentPlayer);
		triggerEndTurnEffects(previousPlayer);
		drawCards();
		if (Rules.turnTimer == Turn.on)
			TurnTimer.getInstance().resetTimer();

			changeGUI(Core.getInstance().getCurrentPlayer());


		}
	

	public void changeGUI(Player p) {
		changeHandViewPanel(p);
		broadcast(p);
	}

	private Player getNextPlayer() {
		Player cp = Core.getInstance().getCurrentPlayer();;
		Player ncp = null;
		Player firstPlayer = Core.getInstance().getPlayers().get(0);
		
		if (cp == null && firstPlayer != null)
			ncp = firstPlayer;
		else if (cp.getPlayerId() + 1 == Core.getInstance().getPlayers().size())
			ncp = firstPlayer;
		else
			ncp = Core.getInstance().getPlayers().get(cp.getPlayerId() + 1);

		return ncp;
	}

	/**
	 * finds and adds all income for the given Player
	 * 
	 * @param p
	 */
	private void addIncome(Player p) {
		p.addGold(TurnUtil.getGoldIncome(p));
		p.addMana(TurnUtil.getManaIncome(p));
		System.out.println("Gathering " + TurnUtil.getGoldIncome(p) + " gold and " + TurnUtil.getManaIncome(p)
				+ " mana from " + MapUtil.getTiles(p).size() + " tiles");
	}

	/**
	 * Resets all actions for all cards, owned by all players.
	 */
	private void resetActionsForAllCards() {
		for (Card c : Core.getInstance().getAllCards()) {
			if (c instanceof CreatureCard) {
				CreatureCard creatureCard = (CreatureCard) c;
				creatureCard.resetActions();
			}

		}
	}

	/**
	 * Activates EffectType.triggerOnTurnEnd effects for all creatures owned by
	 * given Player
	 * 
	 * @param p
	 */
	private void triggerEndTurnEffects(Player p) {
		for (Card c : Core.getInstance().getAllCards()) {
			if (c.getOwner() == p) {
				for (Effect e : EffectUtil.getSubList(c.getEffects(),
						EffectType.triggerOnTurnEnd)) {
					e.triggerOnTurnEnd();

				}
			}
		}
	}

	private void drawCards() {
		Player cp = Core.getInstance().getCurrentPlayer();
	
		if (Core.getInstance().getTurn() == 1)
			CardDrawer.getInstance().drawStartingHand(cp);
		else if (cp.getHand().size() < cp.getHandSize())
			CardDrawer.getInstance().drawCard(cp);
	}

	private void broadcast(Player p) {
		this.setChanged();
		this.notifyObservers(p);
	}

	/**
	 * Changes the view for the HandViewPanel.
	 * 
	 * @param p
	 */
	private void changeHandViewPanel(Player p) {
		HandViewPanel.getInstance().setOwningPlayer(p);
	}
}
